﻿using GoodroommateComputingPlatform.Tasks;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace GoodroommateComputingPlatform.Tasks
{
    public class TaskManagerLegacy : ITaskManager
    {

        /// <summary>
        /// 任务基本信息
        /// </summary>
        private class TaskS
        {
            public TaskDelegate Action { get; set; }
            public TaskDelegateWithProgressReoprt ActionWithProgressReoprt { get; set; }
            public object Globls { get; set; }
            public bool Busy { get; set; }
            public int SuccessCount { get; set; }
            public int FailureCount { get; set; }
            public DateTime LastSuccessDateTime { get; set; }
            public DateTime LastFailureDateTime { get; set; }
            public bool SupportProgressReport { get; set; }
            public long CompletedUnitsCount { get; set; }
            public long TotalUnitsCount { get; set; }

            internal void UpdateProgress(long completedUnitsCount, long totalUnitsCount)
            {
                CompletedUnitsCount = completedUnitsCount;
                TotalUnitsCount = totalUnitsCount;
            }
        }

        // 基本数据
        private Dictionary<string, TaskS> tasks = new Dictionary<string, TaskS>();
        private ILogger<TaskManagerLegacy> _logger;

        private DateTime _startupTime;
        
        
        public TaskManagerLegacy(ILogger<TaskManagerLegacy> logger)
        {
            _logger = logger;
            _startupTime = DateTime.Now;
        }

        //获取管理器信息
        public TaskManagerStatus GetStatus()
        {
            return new TaskManagerStatus()
            {
                Name = "LegacyTaskManager",
                StartupDateTime = _startupTime
            };
        }

        //任务注册
        public void RegisterTask(string name, TaskDelegate action, object globals)
        {
            lock (tasks)
            {
                if (tasks.ContainsKey(name))
                    throw new ArgumentException(nameof(name));
                TaskS task = new TaskS()
                {
                    Action = action,
                    Globls = globals
                };
                tasks.Add(name, task);
            }
        }

        // 任务注册
        public void RegisterTask(string name, TaskDelegateWithProgressReoprt action, object globals)
        {
            lock (tasks)
            {
                if (tasks.ContainsKey(name))
                    throw new ArgumentException(nameof(name));
                TaskS task = new TaskS()
                {
                    ActionWithProgressReoprt = action,
                    Globls = globals
                };
                tasks.Add(name, task);
            }
        }

        //查询任务状态
        public bool IsBusy(string name)
        {
            if (!tasks.ContainsKey(name))
                throw new ArgumentException(nameof(name));
            return tasks[name].Busy;
        }

        //获取任务状态
        public TaskStatus GetTaskStatus(string name)
        {
            lock (tasks)
            {
                if (!tasks.ContainsKey(name))
                    throw new ArgumentException(nameof(name));
                var task = tasks[name];
                return ToTaskStatus(task, name);
            }
        }

        //获取所有任务
        public IEnumerable<TaskStatus> GetAllTasks()
        {
            lock (tasks)
            {
                return tasks.Select(t => ToTaskStatus(t.Value, t.Key)).ToArray();
            }
        }

        private static TaskStatus ToTaskStatus(TaskS task, string name)
        {
            return new TaskStatus()
            {
                Name = name,
                IsBusy = task.Busy,
                SuccessCount = task.SuccessCount,
                FailureCount = task.FailureCount,
                LastSuccessDateTime = task.LastSuccessDateTime,
                LastFailureDateTime = task.LastFailureDateTime,
                TotalUnitsCount = task.TotalUnitsCount,
                CompletedUnitsCount = task.CompletedUnitsCount
            };
        }

        #region 任务调度


        //开始任务
        public void StartTask(string name, object state, TaskCallback callback)
        {
            TaskS task = null;
            lock (tasks)
            {
                if (!tasks.ContainsKey(name))
                    throw new ArgumentException(nameof(name));
                task = tasks[name];
                if (task.Busy)
                    throw new InvalidOperationException();
                task.Busy = true;
            }
            StartTaskInternal(name, task, state, callback);
        }

        //开始任务
        public void StartTaskIfIdle(string name, object state, TaskCallback callback)
        {
            TaskS task = null;
            lock (tasks)
            {
                if (!tasks.ContainsKey(name))
                    throw new ArgumentException(nameof(name));
                task = tasks[name];
                if (task.Busy)
                    throw new InvalidOperationException();
                task.Busy = true;
            }
            StartTaskInternal(name, task, state, callback);
        }

        private void StartTaskInternal(string name, TaskS task, object state, TaskCallback callback)
        {
            task.CompletedUnitsCount = task.TotalUnitsCount = 0;
            TaskDetail detail = new TaskDetail()
            {
                TaskManager = this,
                Name = name,
                TaskInfo = task,
                State = state,
                Callback = callback
            };
            Thread t = new Thread(WorkThread);
            t.Start(detail);
        }

        private class TaskDetail
        {
            internal TaskManagerLegacy TaskManager { get; set; }
            internal TaskS TaskInfo { get; set; }
            public string Name { get; set; }
            public object State { get; set; }
            public object ReturnValue { get; set; }
            public Exception Exception { get; set; }
            public TaskCallback Callback { get; set; }
        }

        private static void WorkThread(object obj)
        {
            var task = (TaskDetail)obj;
            bool isSuccess;
            try
            {
                var taskInfo = task.TaskInfo;
                if (taskInfo.ActionWithProgressReoprt != null)
                    task.ReturnValue = taskInfo.ActionWithProgressReoprt.Invoke(taskInfo.Globls, task.State, taskInfo.UpdateProgress);
                else
                    task.ReturnValue = taskInfo.Action.Invoke(taskInfo.Globls, task.State);
                isSuccess = true;
            }
            catch (Exception e)
            {
                task.Exception = e;
                isSuccess = false;
            }

            lock (task.TaskManager.tasks)
            {
                var t = task.TaskManager.tasks[task.Name];
                t.Busy = false;
                if (isSuccess)
                {
                    t.SuccessCount++;
                    t.LastFailureDateTime = DateTime.Now;
                }
                else
                {
                    t.FailureCount++;
                    t.LastFailureDateTime = DateTime.Now;
                }
            }

            try
            {
                if (task.Exception != null)
                    task.TaskManager._logger.LogError(EventIds.TaskThrowException, task.Exception, task.Name);
                if (task.Callback != null)
                    task.Callback.Invoke(task.ReturnValue, task.Exception);
            }
            catch (Exception e)
            {
                task.TaskManager._logger.LogError(EventIds.CallbackError, e, task.Name);
            }

        }

        #endregion


    }
}
